import logging
import pytest
from utils.get_keyword import GetKeywords

class BaseAsserts:
    """
    封装基础的断言内容
    """

    @staticmethod
    def assume_msg(bool_res,check_name,result, expected):
        """
        优化后的断言方法，兼容Allure报告
        """
        assert_msg = f"校验字段：{check_name},预期结果: {expected}, 实际结果: {result}"
        if not bool_res:
            logging.error(f" ❌ 断言失败！{assert_msg}")
        else:
            logging.info(f" ✅ 断言成功：{assert_msg}")
        pytest.assume(bool_res, assert_msg)


        # assert_msg = f"预期结果: {expected}, 实际结果: {result}"
        # pytest.assume(bool_res, assert_msg)


    @staticmethod
    def status_code_assert(status_code,result):
        """
        返回值状态码的断言方式
        :param status_code: 预期结果状态码
        :param result: 实际结果（http响应值）
        :return: 布尔值
        """
        res = GetKeywords().get_keyword(result,"status_code")
        return res == status_code

    @staticmethod
    def code_assert(code,result):
        """
        返回值code的断言方式
        :param code: 预期结果的code
        :param result: 实际结果的code
        :return: 布尔值
        """
        res = GetKeywords().get_keyword(result,"code")
        return res == code

    @staticmethod
    def str_assert(check_name,result):
        """
        判断字符串是否在响应的结果里
        :param check_name: 预期结果
        :param result: 实际的返回值
        :return: 布尔值
        """
        return check_name in str(result)

    @staticmethod
    def type_assert(expected_type,check_name):
        """
        类型断言
        :param expected_type: 期望的类型
        :param check_name: 检查的字段
        :return:
        """
        return isinstance(check_name,expected_type)

    @staticmethod
    def time_assert(response_time,expected_time):
        """
        响应时间断言
        :param response_time: 实际响应时间
        :param expected_time: 期望响应时间
        :return:
        """
        return response_time <= expected_time





class MainAsserts(BaseAsserts):
    """
    判断什么情况下调用什么断言方法
    """
    def __init__(self,case,result):
        """
        :param case: excel中解析出来的case数据
        :param result: 接口响应结果，字典
        """
        self.__case = case
        self.__result =result

    def main_assert(self):
        for key,value in eval(self.__case["check"]).items():

            if key == "status_code":
                logging.info(f"3.HTTP多重响应内容（status_code）:预期结果{value} in 实际结果{self.__result}")
                self.assume_msg(self.status_code_assert(value,self.__result),"status_code",self.__result,value)

            if key == "code":
                logging.info(f"3.HTTP多重响应内容（code）:预期结果{value} in 实际结果{self.__result}")
                self.assume_msg(self.code_assert(value,self.__result),"code",self.__result,value)

            if key == "str":
                for v in value:
                    # 为什么写成元组的形式：
                    # 因为断言的时候可能会去断言多个字符串是否存在返回值
                    logging.info(f"3.HTTP多重响应内容（str）:预期结果{v} in 实际结果{self.__result}")
                    self.assume_msg(self.str_assert(v,self.__result),"响应文本(str)",self.__result,v)

            if key == "type":
                # 1.在返回值里面不只是一个字段需要做类型断言，type写成一个元组，里面存放多个字段
                for v in value:
                    check_name = v.get("check_name")
                    check_type =v.get("check_type")
                    index = v.get("index")

                    # 2.返回的字段里面，某一个字段可能有多个值，都需要断言
                    #   多个值都需要断言，因此新增一个index为all的逻辑
                    if index == "all":
                        res_list = GetKeywords.get_keywords(self.__result,check_name)
                        # 从响应值里提取的字段列表需要去循环出来，然后放到新的类型列表里面去，再逐个判断
                        for res in res_list:
                            logging.info(f"3.HTTP多重响应内容（type）:校验字段：{check_name},预期结果{check_type}==实际结果{type(res)}")
                            self.assume_msg(self.type_assert(check_type,res),check_name,type(res),check_type)

                    if isinstance(index,int):
                        # 通过index去获取第几个数据进行判断
                        res = GetKeywords.get_keyword(self.__result,check_name,index)
                        logging.info(f"3.HTTP多重响应内容（type）:校验字段：{check_name},预期结果{check_type}==实际结果{type(res)}")
                        self.assume_msg(self.type_assert(check_type,res),check_name,type(res),check_type)


            if key == "time":
                response_time = GetKeywords.get_keyword(self.__result,"response_time")
                logging.info(f"3.HTTP多重响应内容（time）:预期结果{value} >= 实际结果 {response_time}")
                self.assume_msg(self.time_assert(response_time,value),"响应时间",response_time,value)



